//+------------------------------------------------------------------+
//|                                                        Curve.mqh |
//|                             Copyright 2000-2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include <Object.h>                // 基础对象类（CObject），提供对象管理能力
#include <Canvas/Canvas.h>         // 画布类（CCanvas），支撑图形绘制操作

// 前置声明：CGraphic 类（曲线所属的图形容器，避免循环引用）
class CGraphic;

/**
 * @brief 自定义曲线绘制函数指针：用于实现完全自定义的曲线绘制逻辑
 * @param x [in] X轴坐标数组（曲线的水平坐标集合）
 * @param y [in] Y轴坐标数组（曲线的垂直坐标集合，与x数组长度一致）
 * @param size [in] 坐标数组长度（曲线包含的点数）
 * @param graphic [in] 曲线所属的图形容器（CGraphic 实例，提供绘图上下文）
 * @param canvas [in] 绘图画布（CCanvas 实例，用于执行具体绘制操作）
 * @param cbdata [in] 自定义回调数据（传递额外配置信息，如绘制参数、状态等）
 * @note 仅当曲线类型为 CURVE_CUSTOM 时生效，替代内置绘制逻辑
 */
typedef void(*PlotFunction)(double &x[], double &y[], int size, CGraphic *graphic, CCanvas *canvas, void *cbdata);

/**
 * @brief 曲线函数指针：用于通过数学函数生成曲线（如正弦函数、指数函数）
 * @param x [in] 输入的X轴坐标（函数自变量）
 * @return double - 对应的Y轴坐标（函数因变量，即曲线在该X位置的Y值）
 * @example 生成正弦曲线：CurveFunction sinFunc = [](double x){ return MathSin(x); };
 */
typedef double(*CurveFunction)(double);

/**
 * @brief 曲线绘制类型枚举：定义曲线的可视化形态（内置绘制逻辑）
 */
enum ENUM_CURVE_TYPE
  {
   CURVE_POINTS,            // 仅显示数据点（不连接线条，如散点图）
   CURVE_LINES,             // 仅显示连接线条（不显示数据点，如折线图）
   CURVE_POINTS_AND_LINES,  // 同时显示数据点和连接线条（如带标记的折线图）
   CURVE_STEPS,             // 阶梯线（相邻点通过水平+垂直线连接，如步进图）
   CURVE_HISTOGRAM,         // 柱状图（每个数据点对应垂直或水平柱形）
   CURVE_CUSTOM,            // 自定义绘制（通过 PlotFunction 实现完全自定义逻辑）
   CURVE_NONE               // 不绘制（仅存储数据，不显示）
  };

/**
 * @brief 数据点形状枚举：定义 CURVE_POINTS 相关类型中数据点的外观
 */
enum ENUM_POINT_TYPE
  {
   POINT_CIRCLE,            // 圆形
   POINT_SQUARE,            // 正方形
   POINT_DIAMOND,           // 菱形
   POINT_TRIANGLE,          // 正三角形（顶点朝上）
   POINT_TRIANGLE_DOWN,     // 倒三角形（顶点朝下）
   POINT_X_CROSS,           // X形交叉线
   POINT_PLUS,              // 十字形（+）
   POINT_STAR,              // 星形
   POINT_HORIZONTAL_DASH,   // 水平短线
   POINT_VERTICAL_DASH      // 垂直短线
  };

//+------------------------------------------------------------------+
//| CPoint2D 结构体：二维笛卡尔坐标系中的点                          |
//| 核心作用：封装单个点的 X/Y 坐标，用于批量传递曲线的坐标数据        |
//| 适用场景：当曲线数据以“点集合”形式存在时（如鼠标点击的坐标序列）    |
//+------------------------------------------------------------------+
struct CPoint2D
  {
   double x;  // X轴坐标（水平方向，如时间、类别索引）
   double y;  // Y轴坐标（垂直方向，如数值、指标值）
  };

//+------------------------------------------------------------------+
//| CCurve 类：二维图形曲线核心类（继承自 CObject，支持对象管理）       |
//| 核心定位：封装“数据存储+可视化配置+趋势分析”三位一体的曲线能力，    |
//|           为各类二维图形（如折线图、散点图、柱状图）提供统一的曲线管理 |
//| 核心特性：                                                      |
//|  1. 多源数据适配：支持通过 Y数组、(X,Y)数组、点集合、数学函数四种方式生成曲线； |
//|  2. 丰富可视化形态：内置6种绘制类型（点、线、点线结合等），支持数据点形状、线条样式、颜色等精细化配置； |
//|  3. 动态数据更新：提供多种 Update 方法，支持曲线数据实时刷新（无需重新创建实例）； |
//|  4. 趋势分析能力：自动计算线性趋势线系数（基于最小二乘法），支持趋势线显示与隐藏； |
//|  5. 高度可扩展：支持完全自定义绘制逻辑（通过 PlotFunction），适配特殊可视化需求； |
//| 适用场景：所有需要绘制二维曲线的场景，典型如：                    |
//|  - 金融指标展示（如均线、MACD、RSI 等技术指标曲线）；              |
//|  - 数据统计分析（如销量趋势图、用户增长折线图、分类数据柱状图）；   |
//|  - 实时监控曲线（如CPU使用率、内存占用率的动态变化曲线）；         |
//|  - 数学函数可视化（如绘制正弦曲线、指数函数曲线用于教学或分析）；   |
//+------------------------------------------------------------------+
class CCurve : public CObject
  {
private:
   uint              m_clr;                  // 曲线主颜色（线条、柱形的默认颜色）
   double            m_x[];                  // X轴坐标数组（存储曲线的水平坐标数据）
   double            m_y[];                  // Y轴坐标数组（存储曲线的垂直坐标数据，与m_x长度一致）
   double            m_xmin;                 // X轴坐标最小值（自动计算，用于图形范围适配）
   double            m_xmax;                 // X轴坐标最大值（自动计算，用于图形范围适配）
   double            m_ymin;                 // Y轴坐标最小值（自动计算，用于图形范围适配）
   double            m_ymax;                 // Y轴坐标最大值（自动计算，用于图形范围适配）
   int               m_size;                 // 曲线包含的点数（m_x/m_y数组的有效长度）
   ENUM_CURVE_TYPE   m_type;                 // 曲线绘制类型（决定内置绘制逻辑）
   string            m_name;                 // 曲线名称（用于标识，如“MA5均线”“成交量”）
   //--- 线条相关配置（适用于 CURVE_LINES/CURVE_POINTS_AND_LINES/CURVE_STEPS）
   ENUM_LINE_STYLE   m_lines_style;          // 线条样式（如实线、虚线、点线，默认 STYLE_SOLID）
   ENUM_LINE_END     m_lines_end_style;      // 线条端点样式（如圆角、平角，默认 LINE_END_ROUND）
   int               m_lines_width;          // 线条宽度（单位：像素，默认1）
   bool              m_lines_smooth;         // 线条平滑开关（true=绘制平滑曲线，默认false）
   double            m_lines_tension;        // 平滑线条张力（0~1，值越大曲线越陡峭，默认0.5）
   double            m_lines_step;           // 平滑线条采样步长（步长越小曲线越平滑，默认1.0）
   //--- 数据点相关配置（适用于 CURVE_POINTS/CURVE_POINTS_AND_LINES）
   int               m_points_size;          // 数据点大小（单位：像素，默认6）
   ENUM_POINT_TYPE   m_points_type;          // 数据点形状（默认 POINT_CIRCLE）
   bool              m_points_fill;          // 数据点填充开关（true=实心，false=空心，默认false）
   uint              m_points_clr;           // 数据点颜色（默认与曲线主颜色一致）
   //--- 阶梯线相关配置（适用于 CURVE_STEPS）
   int               m_steps_dimension;      // 阶梯线方向（0=垂直优先，1=水平优先，默认0）
   //--- 柱状图相关配置（适用于 CURVE_HISTOGRAM）
   int               m_hisogram_width;       // 柱形宽度（单位：像素，默认1）
   //--- 自定义绘制相关配置（适用于 CURVE_CUSTOM）
   PlotFunction      m_custom_plot_func;     // 自定义绘制函数（替代内置绘制逻辑）
   void             *m_custom_plot_cbdata;   // 自定义绘制回调数据（传递给 m_custom_plot_func）
   //--- 通用配置
   bool              m_visible;              // 曲线显示开关（true=显示，false=隐藏，默认false）
   //--- 趋势线相关配置
   uint              m_trend_clr;            // 趋势线颜色（默认与曲线主颜色一致）
   bool              m_trend_visible;        // 趋势线显示开关（true=显示，默认false）
   //--- 趋势线计算缓存
   bool              m_trend_calc;           // 趋势线系数计算状态（true=已计算，避免重复计算）
   double            m_trend_coeff[];        // 趋势线系数数组（存储线性回归的斜率和截距）

public:
   /**
    * @brief 构造函数1：通过 Y轴数组创建曲线（X轴自动生成连续整数，从0开始）
    * @param y [in] Y轴坐标数组（曲线的数值数据，如指标值、成交量）
    * @param clr [in] 曲线主颜色（如 clrRed、0x3366CC）
    * @param type [in] 曲线绘制类型（如 CURVE_LINES、CURVE_POINTS_AND_LINES）
    * @param name [in] 曲线名称（用于标识）
    * @example 生成5日均线（X轴为0~n-1，Y轴为均线数值）：CCurve ma5(yArray, clrBlue, CURVE_LINES, "MA5");
    */
                     CCurve(const double &y[], const uint clr, ENUM_CURVE_TYPE type, const string name);

   /**
    * @brief 构造函数2：通过 (X,Y) 双数组创建曲线（X轴为自定义坐标，如时间戳）
    * @param x [in] X轴坐标数组（如时间戳、类别索引，需与y数组长度一致）
    * @param y [in] Y轴坐标数组（曲线的数值数据）
    * @param clr [in] 曲线主颜色
    * @param type [in] 曲线绘制类型
    * @param name [in] 曲线名称
    * @example 生成按时间排序的价格曲线（X轴为datetime时间戳，Y轴为价格）
    */
                     CCurve(const double &x[], const double &y[], const uint clr, ENUM_CURVE_TYPE type, const string name);

   /**
    * @brief 构造函数3：通过点集合（CPoint2D数组）创建曲线
    * @param points [in] 点集合数组（每个元素包含X/Y坐标，需与曲线点数一致）
    * @param clr [in] 曲线主颜色
    * @param type [in] 曲线绘制类型
    * @param name [in] 曲线名称
    * @example 生成鼠标点击轨迹曲线（points数组存储每次点击的坐标）
    */
                     CCurve(const CPoint2D &points[], const uint clr, ENUM_CURVE_TYPE type, const string name);

   /**
    * @brief 构造函数4：通过数学函数生成曲线（自动采样X轴坐标，计算对应Y值）
    * @param function [in] 曲线函数（输入X返回Y，如 MathSin、自定义函数）
    * @param from [in] X轴采样起始值（如 0.0）
    * @param to [in] X轴采样结束值（如 2*MathPi）
    * @param step [in] X轴采样步长（步长越小点数越多，曲线越平滑，如 0.1）
    * @param clr [in] 曲线主颜色
    * @param type [in] 曲线绘制类型
    * @param name [in] 曲线名称
    * @example 生成0~2π的正弦曲线：CCurve sinCurve(MathSin, 0, 2*MathPi, 0.1, clrRed, CURVE_LINES, "Sin Curve");
    */
                     CCurve(CurveFunction function, const double from, const double to, const double step, const uint clr, ENUM_CURVE_TYPE type, const string name);

   /**
    * @brief 析构函数：清理曲线资源
    * @note 释放 X/Y 坐标数组、趋势线系数数组等动态内存
    */
                    ~CCurve(void);

   //----------------------------------------------------------------
   // 数据获取接口（获取曲线的坐标数据与统计信息）
   //----------------------------------------------------------------
   /** @brief 获取X轴坐标数组（通过引用输出，数组长度=Size()） */
   void              GetX(double &x[]) const { ArrayCopy(x, m_x); }
   /** @brief 获取Y轴坐标数组（通过引用输出，数组长度=Size()） */
   void              GetY(double &y[]) const { ArrayCopy(y, m_y); }
   /** @brief 获取X轴坐标最大值 */
   double            XMax(void) const { return(m_xmax); }
   /** @brief 获取X轴坐标最小值 */
   double            XMin(void) const { return(m_xmin); }
   /** @brief 获取Y轴坐标最大值 */
   double            YMax(void) const { return(m_ymax); }
   /** @brief 获取Y轴坐标最小值 */
   double            YMin(void) const { return(m_ymin); }
   /** @brief 获取曲线包含的点数（X/Y数组的有效长度） */
   int               Size(void) const { return(m_size); }

   //----------------------------------------------------------------
   // 数据更新接口（动态刷新曲线数据，避免重新创建实例）
   //----------------------------------------------------------------
   /**
    * @brief 更新曲线数据（仅更新Y轴，X轴保持连续整数）
    * @param y [in] 新的Y轴坐标数组（长度需与原数组一致，或自动适配长度）
    */
   void              Update(const double &y[]);

   /**
    * @brief 更新曲线数据（同时更新X轴和Y轴）
    * @param x [in] 新的X轴坐标数组
    * @param y [in] 新的Y轴坐标数组（需与x数组长度一致）
    */
   void              Update(const double &x[], const double &y[]);

   /**
    * @brief 更新曲线数据（通过点集合更新X/Y轴）
    * @param points [in] 新的点集合数组（每个元素包含X/Y坐标）
    */
   void              Update(const CPoint2D &points[]);

   /**
    * @brief 更新曲线数据（通过数学函数重新采样生成X/Y轴）
    * @param function [in] 新的曲线函数
    * @param from [in] 新的X轴采样起始值
    * @param to [in] 新的X轴采样结束值
    * @param step [in] 新的X轴采样步长
    */
   void              Update(CurveFunction function, const double from, const double to, const double step);

   //----------------------------------------------------------------
   // 通用配置接口（Getter/Setter，控制曲线整体属性）
   //----------------------------------------------------------------
   /** @brief 获取曲线主颜色 */
   uint              Color(void) const { return(m_clr); }
   /** @brief 设置曲线主颜色（影响线条、柱形的默认颜色） */
   void              Color(const uint clr) { m_clr = clr; }

   /** @brief 获取曲线绘制类型 */
   int               Type(void) const { return(m_type); }
   /** @brief 设置曲线绘制类型（切换后需重新绘制生效） */
   void              Type(const int type) { m_type = (ENUM_CURVE_TYPE)type; }

   /** @brief 获取曲线名称 */
   string            Name(void) const { return(m_name); }
   /** @brief 设置曲线名称（用于标识或图例显示） */
   void              Name(const string name) { m_name = name; }

   /** @brief 获取曲线显示状态 */
   bool              Visible(void) const { return(m_visible); }
   /** @brief 设置曲线显示状态（true=显示，false=隐藏） */
   void              Visible(const bool visible) { m_visible = visible; }

   //----------------------------------------------------------------
   // 线条配置接口（仅适用于线条相关绘制类型）
   //----------------------------------------------------------------
   /** @brief 获取线条样式 */
   ENUM_LINE_STYLE   LinesStyle(void) const { return(m_lines_style); }
   /** @brief 设置线条样式（如实线 STYLE_SOLID、虚线 STYLE_DASH） */
   void              LinesStyle(ENUM_LINE_STYLE style) { m_lines_style = style; }

   /** @brief 获取线条端点样式 */
   ENUM_LINE_END     LinesEndStyle(void) const { return(m_lines_end_style); }
   /** @brief 设置线条端点样式（如圆角 LINE_END_ROUND、平角 LINE_END_FLAT） */
   void              LinesEndStyle(ENUM_LINE_END end_style) { m_lines_end_style = end_style; }

   /** @brief 获取线条宽度 */
   int               LinesWidth(void) const { return(m_lines_width); }
   /** @brief 设置线条宽度（单位：像素，值越大线条越粗） */
   void              LinesWidth(const int width) { m_lines_width = width; }

   /** @brief 获取线条平滑状态 */
   bool              LinesSmooth(void) const { return(m_lines_smooth); }
   /** @brief 设置线条平滑状态（true=绘制贝塞尔平滑曲线，false=绘制折线） */
   void              LinesSmooth(const bool smooth) { m_lines_smooth = smooth; }

   /** @brief 获取平滑线条张力 */
   double            LinesSmoothTension(void) const { return(m_lines_tension); }
   /** @brief 设置平滑线条张力（0~1，值越大曲线弯曲越明显） */
   void              LinesSmoothTension(const double tension) { m_lines_tension = tension; }

   /** @brief 获取平滑线条采样步长 */
   double            LinesSmoothStep(void) const { return(m_lines_step); }
   /** @brief 设置平滑线条采样步长（步长越小，采样点越多，曲线越平滑） */
   void              LinesSmoothStep(const double step) { m_lines_step = step; }

   //----------------------------------------------------------------
   // 数据点配置接口（仅适用于数据点相关绘制类型）
   //----------------------------------------------------------------
   /** @brief 获取数据点大小 */
   int               PointsSize(void) const { return(m_points_size); }
   /** @brief 设置数据点大小（单位：像素，值越大点越明显） */
   void              PointsSize(const int size) { m_points_size = size; }

   /** @brief 获取数据点形状 */
   ENUM_POINT_TYPE   PointsType(void) const { return(m_points_type); }
   /** @brief 设置数据点形状（如圆形 POINT_CIRCLE、正方形 POINT_SQUARE） */
   void              PointsType(ENUM_POINT_TYPE type) { m_points_type = type; }

   /** @brief 获取数据点填充状态 */
   bool              PointsFill(void) const { return(m_points_fill); }
   /** @brief 设置数据点填充状态（true=实心点，false=空心点） */
   void              PointsFill(const bool fill) { m_points_fill = fill; }

   /** @brief 获取数据点颜色 */
   uint              PointsColor(void) const { return(m_points_clr); }
   /** @brief 设置数据点颜色（可与曲线主颜色不同，用于突出显示） */
   void              PointsColor(const uint clr) { m_points_clr = clr; }

   //----------------------------------------------------------------
   // 阶梯线配置接口（仅适用于 CURVE_STEPS）
   //----------------------------------------------------------------
   /** @brief 获取阶梯线方向（维度） */
   int               StepsDimension(void) const { return(m_steps_dimension); }
   /** @brief 设置阶梯线方向（0=垂直优先，1=水平优先） */
   void              StepsDimension(const int dimension) { m_steps_dimension = dimension; }

   //----------------------------------------------------------------
   // 柱状图配置接口（仅适用于 CURVE_HISTOGRAM）
   //----------------------------------------------------------------
   /** @brief 获取柱形宽度 */
   int               HistogramWidth(void) const { return(m_hisogram_width); }
   /** @brief 设置柱形宽度（单位：像素，值越大柱形越宽） */
   void              HistogramWidth(const int width) { m_hisogram_width = width; }

   //----------------------------------------------------------------
   // 自定义绘制配置接口（仅适用于 CURVE_CUSTOM）
   //----------------------------------------------------------------
   /** @brief 获取自定义绘制函数 */
   PlotFunction      CustomPlotFunction(void) const { return(m_custom_plot_func); }
   /** @brief 设置自定义绘制函数（替代内置绘制逻辑） */
   void              CustomPlotFunction(PlotFunction func) { m_custom_plot_func = func; }

   /** @brief 获取自定义绘制回调数据 */
   void*             CustomPlotCBData(void) const { return(m_custom_plot_cbdata); }
   /** @brief 设置自定义绘制回调数据（传递给自定义绘制函数） */
   void              CustomPlotCBData(void *cbdata) { m_custom_plot_cbdata = cbdata; }

   //----------------------------------------------------------------
   // 趋势线配置与分析接口
   //----------------------------------------------------------------
   /** @brief 获取趋势线显示状态 */
   bool              TrendLineVisible(void) const { return(m_trend_visible); }
   /** @brief 设置趋势线显示状态（true=显示线性趋势线，false=隐藏） */
   void              TrendLineVisible(const bool visible) { m_trend_visible = visible; }

   /** @brief 获取趋势线颜色 */
   uint              TrendLineColor(void) const { return(m_trend_clr); }
   /** @brief 设置趋势线颜色（可与曲线主颜色不同） */
   void              TrendLineColor(const uint clr) { m_trend_clr = clr; }

   /**
    * @brief 获取趋势线系数（线性回归结果）
    * @param coefficients [out] 趋势线系数数组（长度为2，[0]=斜率，[1]=截距，趋势线方程：y = 斜率*x + 截距）
    * @note 若未计算过系数，会自动调用 CalculateCoefficients 计算（基于最小二乘法）
    */
   void              TrendLineCoefficients(double &coefficients[]);

protected:
   /**
    * @brief 计算趋势线系数（线性回归，基于最小二乘法）
    * @note 保护方法，仅内部调用，计算结果存储在 m_trend_coeff 数组中
    */
   virtual void      CalculateCoefficients(void);
  };
//+------------------------------------------------------------------+